# -*- coding: utf-8 -*-
# @Time : 2024/8/6 16:31
# @Author : sdk007

import time

from HCNetSDK import *
import random

class devClass(object):
    def __init__(self):
        self.hikSDK = self.LoadSDK()  # 加载sdk库
        self.iUserID = -1  # 登录句柄
        self.alarmHandle = -1  # 布防句柄
        self.listenHandle = -1  # 监听句柄
        self.basePath = ''  # 基础路径
        self.msg_callback_func = MSGCallBack_V31(self.g_fMessageCallBack_Alarm)  # 注册回调函数实现
        self.status = 0


    def LoadSDK(self):
        hikSDK = None
        try:
            print("netsdkdllpath: ", netsdkdllpath)
            hikSDK = load_library(netsdkdllpath)
        except OSError as e:
            print('动态库加载失败', e)
        return hikSDK

    # 报警信息回调函数实现代码
    def g_fMessageCallBack_Alarm(self, lCommand, pAlarmer, pAlarmInfo, dwBufLen, pUser):
        """
        解析报警信息
        """
        pAlarmer = pAlarmer.contents
        sDeviceIP = str(pAlarmer.sDeviceIP, encoding="gbk").rstrip('\x00')
        sSerialNumber = str(pAlarmer.sSerialNumber, encoding="gbk").rstrip('\x00')
        print(f"lCommand: {hex(lCommand)}, lUserID: {pAlarmer.lUserID}, sDeviceIP: {sDeviceIP}, sSerialNumber: {sSerialNumber}")

        if lCommand == ALARM_LCOMMAND_ENUM.COMM_ALARM_RULE.value:
            strudection = cast(pAlarmInfo,LPNET_VCA_RULE_ALARM).contents

            print("行为事件类型扩展%d" % strudection.struRuleInfo.wEventTypeEx)
            if strudection.struRuleInfo.wEventTypeEx == HIGH_DENSITY:
                from datetime import datetime
                # 获取当前时间戳
                timestamp = datetime.now().strftime('%Y%m%d%H%M%S')
                # 创建文件名
                filename1 = f'image_{timestamp}_1.jpg'
                buff1 = bytes(strudection.pImage [:strudection.dwPicDataLen])
                with open(f'./pic/{filename1}', 'wb') as fp1:
                    fp1.write(buff1)
                print("检测到人员聚集")





        return True

    # 设置SDK初始化依赖库路径
    def SetSDKInitCfg(self):
        # 设置HCNetSDKCom组件库和SSL库加载路径
        if sys_platform == 'windows':
            strPath = os.getcwd().encode('gbk') + b'\lib'
            sdk_ComPath = NET_DVR_LOCAL_SDK_PATH()
            sdk_ComPath.sPath = strPath
            print('strPath: ', strPath)
            if self.hikSDK.NET_DVR_SetSDKInitCfg(NET_SDK_INIT_CFG_TYPE.NET_SDK_INIT_CFG_SDK_PATH.value,
                                                 byref(sdk_ComPath)):
                print('NET_DVR_SetSDKInitCfg: 2 Succ')
            if self.hikSDK.NET_DVR_SetSDKInitCfg(NET_SDK_INIT_CFG_TYPE.NET_SDK_INIT_CFG_LIBEAY_PATH.value,
                                                 create_string_buffer(strPath + b'\libcrypto-1_1-x64.dll')):
                print('NET_DVR_SetSDKInitCfg: 3 Succ')
            if self.hikSDK.NET_DVR_SetSDKInitCfg(NET_SDK_INIT_CFG_TYPE.NET_SDK_INIT_CFG_SSLEAY_PATH.value,
                                                 create_string_buffer(strPath + b'\libssl-1_1-x64.dll')):
                print('NET_DVR_SetSDKInitCfg: 4 Succ')
        else:
            strPath = os.getcwd().encode('utf-8') + b'\lib'
            sdk_ComPath = NET_DVR_LOCAL_SDK_PATH()
            sdk_ComPath.sPath = strPath
            if self.hikSDK.NET_DVR_SetSDKInitCfg(NET_SDK_INIT_CFG_TYPE.NET_SDK_INIT_CFG_SDK_PATH.value,
                                                 byref(sdk_ComPath)):
                print('NET_DVR_SetSDKInitCfg: 2 Succ')
            if self.hikSDK.NET_DVR_SetSDKInitCfg(NET_SDK_INIT_CFG_TYPE.NET_SDK_INIT_CFG_LIBEAY_PATH.value,
                                                 create_string_buffer(strPath + b'/libcrypto.so.1.1')):
                print('NET_DVR_SetSDKInitCfg: 3 Succ')
            if self.hikSDK.NET_DVR_SetSDKInitCfg(NET_SDK_INIT_CFG_TYPE.NET_SDK_INIT_CFG_SSLEAY_PATH.value,
                                                 create_string_buffer(strPath + b'/libssl.so.1.1')):
                print('NET_DVR_SetSDKInitCfg: 4 Succ')
        self.basePath = strPath

    # 通用设置，日志/回调事件类型等
    def GeneralSetting(self):

        # 日志的等级（默认为0）：0-表示关闭日志，1-表示只输出ERROR错误日志，2-输出ERROR错误信息和DEBUG调试信息，3-输出ERROR错误信息、DEBUG调试信息和INFO普通信息等所有信息
        self.hikSDK.NET_DVR_SetLogToFile(3, b'./SdkLog_Python/', False)

        # 通用参数配置
        sdkCfg = NET_DVR_LOCAL_GENERAL_CFG()
        sdkCfg.byAlarmJsonPictureSeparate = 1  # 控制JSON透传报警数据和图片是否分离，0-不分离，1-分离（分离后走COMM_ISAPI_ALARM回调返回）
        self.hikSDK.NET_DVR_SetSDKLocalCfg(NET_SDK_LOCAL_CFG_TYPE.NET_DVR_LOCAL_CFG_TYPE_GENERAL.value, byref(sdkCfg))

        # 设置报警回调函数
        self.hikSDK.NET_DVR_SetDVRMessageCallBack_V31(self.msg_callback_func, None)

    def LoginDev(self, ip, username, pwd):
        # 登录参数，包括设备地址、登录用户、密码等
        struLoginInfo = NET_DVR_USER_LOGIN_INFO()
        struLoginInfo.bUseAsynLogin = 0  # 同步登录方式
        struLoginInfo.sDeviceAddress = ip  # 设备IP地址
        struLoginInfo.wPort = 8000  # 设备服务端口
        struLoginInfo.sUserName = username  # 设备登录用户名
        struLoginInfo.sPassword = pwd  # 设备登录密码
        struLoginInfo.byLoginMode = 0

        # 设备信息, 输出参数
        struDeviceInfoV40 = NET_DVR_DEVICEINFO_V40()

        self.iUserID = self.hikSDK.NET_DVR_Login_V40(byref(struLoginInfo), byref(struDeviceInfoV40))
        if self.iUserID < 0:
            print("Login failed, error code: %d" % self.hikSDK.NET_DVR_GetLastError())
            self.hikSDK.NET_DVR_Cleanup()
        else:
            print('登录成功，设备序列号：%s' % str(struDeviceInfoV40.struDeviceV30.sSerialNumber, encoding="utf8").rstrip('\x00'))

    def SetupAlarm(self):
        # 启用布防
        struAlarmParam = NET_DVR_SETUPALARM_PARAM()
        struAlarmParam.dwSize = sizeof(struAlarmParam)
        struAlarmParam.byAlarmInfoType = 1  # 智能交通报警信息上传类型：0- 老报警信息（NET_DVR_PLATE_RESULT），1- 新报警信息(NET_ITS_PLATE_RESULT)
        struAlarmParam.byDeployType = 1  # 布防类型：0-客户端布防，1-实时布防

        self.alarmHandle = self.hikSDK.NET_DVR_SetupAlarmChan_V41(self.iUserID, byref(struAlarmParam))
        if self.alarmHandle < 0:
            print("NET_DVR_SetupAlarmChan_V41 失败, error code: %d" % self.hikSDK.NET_DVR_GetLastError())
            self.hikSDK.NET_DVR_Logout(self.iUserID)
            self.hikSDK.NET_DVR_Cleanup()
        else:
            print('NET_DVR_SetupAlarmChan_V41 Succ! ')

    def StartListen(self, listenIp, listenPort):
        # 启动报警监听并且设置回调函数接收事件
        self.listenHandle = self.hikSDK.NET_DVR_StartListen_V30(listenIp, listenPort, self.msg_callback_func, None)
        print('self.listenHandle: ', self.listenHandle)
        if self.listenHandle < 0:
            print("NET_DVR_StartListen_V30失败, error code: %d" % self.hikSDK.NET_DVR_GetLastError())
            self.hikSDK.NET_DVR_Cleanup()
            exit()

    def StopListen(self):
        if self.listenHandle > -1:
            # 停止监听
            self.hikSDK.NET_DVR_StopListen_V30(self.listenHandle)

    def StopAlarm(self):
        if self.alarmHandle > -1:
            # 撤销布防，退出程序时调用
            self.hikSDK.NET_DVR_CloseAlarmChan_V30(self.alarmHandle)

    def LogoutDev(self):
        if self.iUserID > -1:
            # 撤销布防，退出程序时调用
            self.hikSDK.NET_DVR_Logout(self.iUserID)


if __name__ == '__main__':
    dev = devClass()
    dev.SetSDKInitCfg()  # 设置SDK初始化依赖库路径
    dev.hikSDK.NET_DVR_Init()  # 初始化sdk
    dev.GeneralSetting()  # 通用设置，日志，回调函数等

    '''
    说明：这里包含布防和监听两种方式，其中，布防方式接收事件需要先布防，监听方式不需要布防，两种方式二选一即可。
    '''
    dev.LoginDev(ip=b'192.168.1.64', username=b"admin", pwd=b"gac13579")  # 登录设备
    dev.SetupAlarm()
    # dev.StartListen(listenIp=b'10.184.68.129', listenPort=7200)

    while True:
        user_input = input("请输入一个字符 (输入 Y 退出): ").strip().upper()
        if user_input == 'Y':
            break
    # dev.StopListen()
    dev.StopAlarm()  # 停止布防
    dev.LogoutDev()  # 登出设备
    dev.hikSDK.NET_DVR_Cleanup()  # 反初始化sdk
